home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
source
/
snip9503
/
serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-14
|
11KB
|
344 lines
/*
+----------------------------------------------------+
| Thunderbird Software |
+----------------------------------------------------+
| Filespec : Serial.c |
| Date : October 24, 1991 |
| Time : 15:03 |
| Revision : 1.1 |
| Update: August 29, 1994 |
+----------------------------------------------------+
| Programmer: Scott Andrews |
| Address : 5358 Summit RD SW |
| City/State: Pataskala, Ohio |
| Zip : 43062 |
+----------------------------------------------------+
| Released to the Public Domain |
+----------------------------------------------------+
*/
/*
+----------------------------------------------------------+
| Call open_serial to install the interrupt handler |
| You must call close_serial before exiting your program |
| or a machine crash will occur! |
+----------------------------------------------------------+
*/
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include "serial.h"
#include "queue.h"
#include "portable.h"
QUEUE *Serial_In_Queue;
QUEUE *Serial_Out_Queue;
OLD_COMM_PARAMS old_comm_params;
COMM_STATUS comm_status;
void (_interrupt _far *oldvector_serial )();
/* save addr for intr handler */
int ComBase; /* Comm port address */
int IrqNum; /* Comm interrupt request */
int OpenComPort ( char Port ) /* install int. handler */
{
unsigned status;
int retval = -1;
/* allocate input and output queues */
Serial_In_Queue = alloc_queue( SerInBufSize );
if ( (QUEUE *) 0 == Serial_In_Queue)
return retval;
Serial_Out_Queue = alloc_queue( SerOutBufSize );
if ( (QUEUE *) 0 == Serial_Out_Queue)
{
free ( Serial_In_Queue );
return retval;
}
retval = 0;
/* Setup Comm base port address and IRQ number */
switch ( Port)
{
case '1': ComBase = 0x3F8; IrqNum = 4; break;
case '2': ComBase = 0x2F8; IrqNum = 3; break;
case '3': ComBase = 0x3E8; IrqNum = 4; break;
case '4': ComBase = 0x2E8; IrqNum = 3; break;
default : ComBase = 0x3F8; IrqNum = 4; break;
}
old_comm_params.int_enable = IN_PORT ( ComBase + INT_EN );
OUT_PORT ( ComBase + INT_EN, 0 ); /* turn off comm interrupts */
/* save old comm parameters */
old_comm_params.line = IN_PORT ( ComBase + LINE_CNTRL );
old_comm_params.modem = IN_PORT ( ComBase + MODEM_CNTRL );
status = IN_PORT ( ComBase + LINE_CNTRL );
OUT_PORT ( ComBase + LINE_CNTRL, (unsigned char) status | 0x80 );
old_comm_params.baud_lsb = IN_PORT ( ComBase + BAUD_LSB );
old_comm_params.baud_msb = IN_PORT ( ComBase + BAUD_MSB );
status = IN_PORT ( ComBase + LINE_CNTRL );
OUT_PORT ( ComBase + LINE_CNTRL, (unsigned char) status | 0x7F );
status = OUT2 | DTR; /* DTR/OUT2 must be set! */
OUT_PORT ( ComBase + MODEM_CNTRL, (unsigned char) status );
/* get serial port address/vector */
oldvector_serial = (void(_interrupt _far *)(void))GETVECT(IrqNum + 8 );
/* set our interrupt handler */
SETVECT ( IrqNum + 8, serial );
/* save the PIC */
old_comm_params.int_cntrl = IN_PORT ( 0x21 );
status = ( 1 << IrqNum); /* calculate int enable bit */
status = ~status;
/* ok enable comm ints */
OUT_PORT ( 0x21, (unsigned char) old_comm_params.int_cntrl &
(unsigned char) status );
return retval;
}
void CloseComPort ( void )
{
int status;
/* restore UART to previous state */
OUT_PORT ( ComBase + INT_EN, (unsigned char) 0 );
OUT_PORT ( ComBase + MODEM_CNTRL,
(unsigned char) old_comm_params.modem );
status = IN_PORT ( ComBase + LINE_CNTRL );
OUT_PORT ( ComBase + LINE_CNTRL,
(unsigned char) status | 0x80 );
OUT_PORT ( ComBase + BAUD_LSB,
(unsigned char) old_comm_params.baud_lsb );
OUT_PORT ( ComBase + BAUD_MSB,
(unsigned char) old_comm_params.baud_msb );
OUT_PORT ( ComBase + LINE_CNTRL,
(unsigned char) old_comm_params.line );
OUT_PORT ( 0x21, (unsigned char) old_comm_params.int_cntrl );
/* restore old interrupt handler */
SETVECT ( IrqNum + 8, oldvector_serial );
/* free input and output queues */
free ( Serial_In_Queue );
free ( Serial_Out_Queue );
return;
}
void InitComPort ( char Baud[], char Databits,
char Parity, char Stopbits )
{
int status;
long baudrate;
unsigned divisor;
/* set baud rate */
status = IN_PORT ( ComBase + LINE_CNTRL );
OUT_PORT ( ComBase + LINE_CNTRL,
(unsigned char) status | 0x80 );
baudrate = atol ( Baud );
if ( baudrate == 0)
baudrate = 2400L;
divisor = (unsigned) ( 115200L / baudrate);
OUT_PORT ( ComBase + BAUD_LSB,
(unsigned char) ( divisor & 0x00FF) );
OUT_PORT ( ComBase + BAUD_MSB,
(unsigned char) ( ( divisor >> 8) & 0x00FF) );
status = 0x00;
/* set parity */
switch ( Parity) /* set parity value */
{
case 'O': /* odd parity */
case 'o':
status = 0x08; break;
case 'E': /* even parity */
case 'e':
status = 0x18; break;
case 'S': /* stick parity */
case 's':
status = 0x28; break;
case 'N': /* no parity */
case 'n':
default : status = 0x00;
}
/* set number data bits */
switch ( Databits)
{
case '5':
break;
case '6':
status = status | 0x01;
break;
case '7':
status = status | 0x02;
break;
case '8':
default :
status = status | 0x03;
}
/* set number stop bits */
switch ( Stopbits)
{
case '2':
status = status | 0x04;
break;
case '1':
default :
;
}
OUT_PORT ( ComBase + LINE_CNTRL, (unsigned char) status );
status = OUT2 | DTR; /* DTR/OUT2 must be set! */
OUT_PORT ( ComBase + MODEM_CNTRL, (unsigned char) status );
/* enable serial interrupts */
OUT_PORT ( ComBase + INT_EN, RX_INT | ERR_INT | RS_INT );
return;
}
void DropDtr ( void )
{
int status;
status = IN_PORT ( ComBase + MODEM_CNTRL );
status &= 0xFE; /* turn off DTR bit */
OUT_PORT ( ComBase + MODEM_CNTRL, (unsigned char) status );
return;
}
void RaiseDtr ( void )
{
int status;
status = IN_PORT ( ComBase + MODEM_CNTRL );
status |= 0x01; /* turn on DTR bit */
OUT_PORT ( ComBase + MODEM_CNTRL, (unsigned char) status );
return;
}
int ComRecChar ( void )
{
return de_queue ( Serial_In_Queue );
}
int ComSendString ( char *string )
{
int retval;
char *pointer;
pointer = string;
while ( *pointer)
{
retval = en_queue ( Serial_Out_Queue, *pointer );
pointer++;
}
if ( 0x0 == (comm_status.modem & 0x40))
RaiseDtr ();
OUT_PORT ( ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT );
return retval;
}
int ComSendChar ( char character )
{
int retval;
/* interrupt driven send */
if ( 0x0 == (comm_status.modem & 0x40))
RaiseDtr ();
retval = en_queue ( Serial_Out_Queue, character );
if ( - 1 != retval)
OUT_PORT ( ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT );
return retval;
}
int ComStatus ( void )
{
unsigned status;
unsigned retval;
retval = IN_PORT ( ComBase + LINE_STATUS );
retval = retval << 8;
status = IN_PORT ( ComBase + MODEM_STATUS );
retval = retval | status;
if ( queue_empty ( Serial_In_Queue ))
retval &= 0xFEFF;
else retval |= 0x0100;
return (int) retval;
}
void _interrupt _far serial ( void ) /* interrupt handler */
{
int temp;
INT_OFF ();
while ( 1)
{
comm_status.intrupt = IN_PORT ( ComBase + INT_ID );
comm_status.intrupt &= 0x0f;
switch ( comm_status.intrupt)
{
case 0x00: /* modem interrupt */
comm_status.modem = IN_PORT( ComBase + MODEM_STATUS );
break;
case 0x02: /* xmit interrupt */
if ( queue_empty ( Serial_Out_Queue ))
OUT_PORT(ComBase + INT_EN, RX_INT|ERR_INT|RS_INT );
else
{
temp = de_queue ( Serial_Out_Queue );
if ( - 1 != temp)
OUT_PORT ( ComBase + XMIT, temp );
}
break;
case 0x04: /* receive interrupt */
en_queue(Serial_In_Queue, (char)IN_PORT(ComBase + REC));
break;
case 0x06: /* line interrupt */
comm_status.line = IN_PORT ( ComBase + LINE_STATUS );
(void) IN_PORT ( ComBase + REC );
en_queue ( Serial_In_Queue, '!' );
break;
default: /* No Mo` Left */
comm_status.modem = IN_PORT ( ComBase + MODEM_STATUS );
OUT_PORT ( 0x20, 0x20 );
INT_ON ();
return;
} /* switch */
} /* while */
}
/* End of Serial.C */